﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using NFit.Core.Interfaces;

namespace NFit.Core.IO
{
    /// <summary>
    /// Reader implementation for text format
    /// </summary>
    public class TextSpecificationReader : TextSpecification, ISpecificationReader
    {        
        /// <summary>
        /// Read a specification from the provided string
        /// </summary>
        /// <param name="s">the string representation of the specification</param>
        /// <returns>spec definition</returns>
        public SpecificationDefinition ReadSpecification(string s)
        {
            SpecificationDefinition res = null;
            using (StringReader reader = new StringReader(s))
            {
                res = ReadSpec(reader);
            }
            return res;
        }

        /// <summary>
        /// Read a specification from the provided stream
        /// </summary>
        /// <param name="stream">the stream providing the specification</param>
        /// <returns>spec definition</returns>
        public SpecificationDefinition ReadSpecification(Stream stream)
        {
            SpecificationDefinition res = null;
            using (StreamReader reader = new StreamReader(stream))
            {
                res = ReadSpec(reader);
            }
            return res;
        }

        private SpecificationDefinition ReadSpec(TextReader reader)
        {
            SpecificationDefinition res = null;

            StringBuilder commentBuffer = new StringBuilder();
            res = new SpecificationDefinition();
            FixtureDefinition currentFixture = null;
            string tmp = null;
            while ((tmp = reader.ReadLine()) != null)
            {
                tmp = tmp.Trim();
                if (string.IsNullOrEmpty(tmp))
                {
                    currentFixture = ProcessBlankLine(currentFixture, ref commentBuffer, res);
                }
                else
                {
                    if (tmp.StartsWith(CommentToken))
                    {
                        ProcessCommentLine(tmp, commentBuffer);
                    }
                    else
                    {
                        currentFixture = ProcessLine(tmp, currentFixture, ref commentBuffer);
                    }
                }
            }

            if (currentFixture != null)
            {
                ProcessBlankLine(currentFixture, ref commentBuffer, res);
            }
            reader.Close();

            return res;
        }

        private FixtureDefinition ProcessLine(string tmp, FixtureDefinition currentFixture, ref StringBuilder commentBuffer)
        {
            if (currentFixture == null)
            {
                currentFixture = new FixtureDefinition();
                if (commentBuffer.Length > 0)
                {
                    currentFixture.Header = commentBuffer.ToString().Trim();
                    commentBuffer = new StringBuilder();
                }
            }
            currentFixture.WithRow(tmp.Split(CellSeparator));
            return currentFixture;
        }

        private void ProcessCommentLine(string lineContent, StringBuilder commentBuffer)
        {
            commentBuffer.AppendLine(lineContent.Substring(CommentToken.Length).Trim());
        }

        private FixtureDefinition ProcessBlankLine(FixtureDefinition currentFixture, ref StringBuilder commentBuffer, SpecificationDefinition res)
        {
            if (currentFixture != null)
            {
                if (commentBuffer.Length > 0)
                {
                    currentFixture.Footer = commentBuffer.ToString().Trim();
                    commentBuffer = new StringBuilder();
                }
                res.Add(currentFixture);
                currentFixture = null;
            }
            return currentFixture;
        }
    }
}
